/*
 * Created on 20 ao�t 2005
 *
 */

package picoevo.gp.evolution;

import java.util.ArrayList;

import picoevo.core.evolution.VariationOperator;
import picoevo.core.representation.EvolutionObject;
import picoevo.gp.representation.Element_Node_TreeGP;
import picoevo.gp.representation.Element_Node_TreeGP_Root;
import picoevo.gp.representation.Individual_TreeGP;
import picoevo.toolbox.Dictionary;

public class VariationOperator_Individual_TreeGP_Mutation extends VariationOperator {

	public VariationOperator_Individual_TreeGP_Mutation(String __name) {
		super(__name);
	}

	public VariationOperator_Individual_TreeGP_Mutation(String __name, double __operatorRate) {
		super(__name, __operatorRate);
	}

	/**
	 * Standard Koza mutation for symbolic regression (cf. GP book vol.1)
	 */
	@Override
	public void applyOperator(EvolutionObject __individual) {
		Individual_TreeGP individual = (Individual_TreeGP) __individual;

		if (Math.random() < individual.getTemplate().getDoubleProperty("MutationRate")) {
			int maxDepthForMutation = individual.getTemplate().getIntProperty("MaxDepth_Mutation");
			Element_Node_TreeGP targetElement;

			if (Math.random() < 0.8 && individual.getNonTerminalElements().size() > 0) // Koza
			// says
			// :
			// 0.8
			// non-terminal
			// vs.
			// 0.2
			// terminal
			{
				ArrayList nonTerminalElements = individual.getNonTerminalElements();
				int randomIndex = (int) ((nonTerminalElements.size() * Math.random()));
				targetElement = ((Element_Node_TreeGP) nonTerminalElements.get(randomIndex));
			} else {
				ArrayList terminalElements = individual.getTerminalElements();
				int randomIndex = (int) ((terminalElements.size() * Math.random()));
				targetElement = ((Element_Node_TreeGP) terminalElements.get(randomIndex));
			}

			int maxDepth;
			if ((maxDepthForMutation + targetElement.getCurrentDepth()) > individual.getTemplate().getIntProperty("MaxRunningDepth"))
				maxDepth = individual.getTemplate().getIntProperty("MaxRunningDepth") - targetElement.getCurrentDepth();
			else
				maxDepth = maxDepthForMutation;

			Element_Node_TreeGP_Root newSubTreeRoot = new Element_Node_TreeGP_Root(individual);
			newSubTreeRoot.performInitialisation(maxDepth, Dictionary.growMethod, false); // Grow
			// tree
			// generation
			// -
			// single
			// terminal
			// is
			// possible
			targetElement.substituteWith((Element_Node_TreeGP) (newSubTreeRoot.getSuccessors().get(0)));
		}
	}
}
